﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.XPath;

using Microsoft.Office.InfoPath;
using InfoPathDebugger.UserControls;

namespace InfoPathDebugger
{
    public partial class WatchSelectForm : Form
    {
        public WatchSelectForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Initialize the watch select form.
        /// </summary>
        public void Initialize()
        {
            if (_dsCol == null)
            {
                throw new MemberAccessException("The _dsCol is null. Please specifies the _dsCol before call Initailize() method.");
            }

            initializeTreeView();
        }

        /// <summary>
        /// Gets or sets the data source collection of the InfoPath form.
        /// </summary>
        public DataSourceCollection DataSourceCollection
        {
            get
            {
                return _dsCol;
            }
            set
            {
                _dsCol = value;
            }
        }

        /// <summary>
        /// Gets the selected fields.
        /// </summary>
        public List<FieldChangedListViewDataItem> SelectedFields
        {
            get
            {
                return _selectedFields;
            }
        }

        private void initializeTreeView()
        {
            trvFields.Nodes.Clear();

            // Add the root of the tree view.
            trvFields.Nodes.Add("Data Sources");

            // Construct tree view.
            foreach (DataSource ds in _dsCol)
            {
                StringBuilder sb = new StringBuilder();
                TreeNode node = trvFields.Nodes[0].Nodes.Add(String.IsNullOrEmpty(ds.Name) ? "Main" : ds.Name);
                XPathNavigator nav = ds.CreateNavigator();
                nav.MoveToChild(XPathNodeType.Element);
                sb.Append("/");
                sb.Append(nav.Name);

                recursiveConstructTreeView(node, nav, sb);
            }
        }

        private void recursiveConstructTreeView(TreeNode root, XPathNavigator navigator, StringBuilder sbCurrentPath)
        {
            String nodeText = navigator.Name;
            if (!XPathHelper.HasChildElement(navigator))
            {
                nodeText += " : " + navigator.Value;
            }

            TreeNode node = new TreeNode(nodeText);
            node.Name = sbCurrentPath.ToString();
            root.Nodes.Add(node);

            if (navigator.MoveToChild(XPathNodeType.Element))
            {
                XPathNavigator tempNav = navigator.Clone();
                StringBuilder sbTemp = new StringBuilder(sbCurrentPath.ToString());
                
                sbTemp.Append("/");
                sbTemp.Append(navigator.Name);

                recursiveConstructTreeView(node, tempNav, sbTemp);

                // If current node has sibling nodes, find the leaf child node of the next node.
                while (navigator.MoveToNext(XPathNodeType.Element))
                {
                    tempNav = navigator.Clone();
                    StringBuilder sbTemp2 = new StringBuilder(sbCurrentPath.ToString());
                    
                    sbTemp2.Append("/");
                    sbTemp2.Append(tempNav.Name);

                    recursiveConstructTreeView(node, tempNav, sbTemp2);
                }
            }
        }

        #region Event Handlers

        private void btnAdd_Click(object sender, EventArgs e)
        {
            // If the selected node is not null, the selected node is not the root and not the first level child of the root,
            // add it to the selected node text box.
            if (trvFields.SelectedNode != null && !trvFields.SelectedNode.Equals(trvFields.Nodes[0]) && !trvFields.SelectedNode.Parent.Equals(trvFields.Nodes[0]))
            {
                String selectedText = makeSelectedText(trvFields.SelectedNode);
                tbSelectedFields.Text += selectedText;
            }
        }

        private String makeSelectedText(TreeNode treeNode)
        {
            String path = treeNode.Name;
            String nodeText = treeNode.Text;
            String defaultValue = String.Empty;
            if (nodeText.Contains(" : "))
            {
                Int32 index = nodeText.IndexOf(" : ");
                Int32 defaultValueIndex = index + 3;
                if (defaultValueIndex < nodeText.Length)
                {
                    defaultValue = nodeText.Substring(defaultValueIndex);
                }

                return path + "$$" + defaultValue + ";\r\n";
            }

            return path + "$$;\r\n";
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            String[] selectedItemTextArray = tbSelectedFields.Text.Split(new String[]{";\r\n"}, StringSplitOptions.RemoveEmptyEntries);
            foreach (String selectedItemText in selectedItemTextArray)
            {
                String[] subText = selectedItemText.Split(new String[]{"$$"}, StringSplitOptions.None);
                FieldChangedListViewDataItem dataItem = new FieldChangedListViewDataItem();
                dataItem.Name = subText[0].Substring(subText[0].LastIndexOf("/") + 1);
                dataItem.NewValue = String.Empty;
                dataItem.OldValue = subText[1];
                dataItem.Operation = String.Empty;
                dataItem.Path = subText[0];
                dataItem.Time = String.Empty;

                _selectedFields.Add(dataItem);
            }

            this.DialogResult = DialogResult.OK;
            this.Close();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        private void tbSelectedFields_TextChanged(object sender, EventArgs e)
        {
            btnOK.Enabled = !String.IsNullOrEmpty(tbSelectedFields.Text);
        }

        #endregion

        private DataSourceCollection _dsCol = null;
        private List<FieldChangedListViewDataItem> _selectedFields = new List<FieldChangedListViewDataItem>();
    }
}
